﻿using System;
using System.Collections.Generic;
using System.Threading;

using SimpleServiceBus.Endpoint;
using SimpleServiceBus.Messages.ControlMessages;
using SimpleServiceBus.Utilities;


namespace SimpleServiceBus.Bus.MessageManagement.Callbacks
{
    public class DefaultCallbackManager : EndpointServiceBase, ICorrelatedCallbackManager
    {
        private readonly ReaderWriterLock _rwLock = new ReaderWriterLock();
        private IDictionary<string, Callback> _listenerTable;

        #region ICorrelatedCallbackManager Members

        public ICallback Register(string correlationId)
        {
            var result = new Callback(correlationId, this);

            using (new WriterLock(_rwLock, TimeSpan.FromSeconds(10)))
            {
                _listenerTable[correlationId] = result;
            }

            return result;
        }

        public void Unregister(string correlationId)
        {
            if (string.IsNullOrEmpty(correlationId))
                return;

            using(new WriterLock(_rwLock,TimeSpan.FromSeconds(10)))
            {
                if (_listenerTable != null && _listenerTable.ContainsKey(correlationId))
                    _listenerTable.Remove(correlationId);
            }
        }

        public bool Notify(string correlationId, object message)
        {
            bool result = false;

            if (String.IsNullOrEmpty(correlationId))
                return result;

            Callback callback = null;

            using (var rl = new ReaderLock(_rwLock, TimeSpan.FromSeconds(10)))
            {
                if (_listenerTable.ContainsKey(correlationId))
                {
                    callback = _listenerTable[correlationId];
                    rl.UpgradeAccessToWrite(TimeSpan.FromSeconds(10));
                    _listenerTable.Remove(correlationId);
                }
            }

            if (callback != null)
            {
                if (message != null)
                {
                    var cm = message as CompletionMessage;
                    if (cm != null)
                        callback.Complete(cm.ErrorCode, null);
                    else
                        callback.Complete(int.MinValue, message);

                    result = true;
                }

            }

            return result;
        }

        #endregion

        protected override void ShutDownService()
        {
            using (new WriterLock(_rwLock, TimeSpan.FromSeconds(10)))
            {
                _listenerTable.Clear();
                _listenerTable = null;
            }
        }

        protected override void StartService()
        {
            _listenerTable = new Dictionary<string, Callback>();
        }
    }
}
